package com.gitee.wsl.struct.tree

import com.gitee.wsl.func.consumer.BiConsumer
import com.gitee.wsl.func.Function
import com.gitee.wsl.func.predicate.Predicate

/**
 * @Description: 树操作方法工具类
 * @Author: 公众号：赵侠客
 * @Copyright: Copyright (c) 赵侠客
 * @Date: 2024-07-22 10:42
 * @Version: 1.0
 */
object QuickTreeHelper {
    /**
     * 使用Map合成树
     *
     * @param menuList       需要合成树的List
     * @param pId            对象中的父ID字段,如:Menu:getPid
     * @param id             对象中的id字段 ,如：Menu:getId
     * @param rootCheck      判断E中为根节点的条件，如：x->x.getPId()==-1L , x->x.getParentId()==null,x->x.getParentMenuId()==0
     * @param setSubChildren E中设置下级数据方法，如： Menu::setSubMenus
     * @param <T>            ID字段类型
     * @param <E>            泛型实体对象
     * @return
    </E></T> */
    fun <T, E> makeTree(
        menuList: List<E>,
        pId: Function<E, T>,
        id: Function<E, T>,
        rootCheck: Predicate<E>,
        setSubChildren: BiConsumer<E, MutableList<E>>,
    ): List<E> {

        val parentMenuMap: MutableMap<T?, MutableList<E>> = LinkedHashMap()

        val result: MutableList<E> = ArrayList<E>()

        //预先构建映射表
        for (node in menuList) {
            val parentId =  pId.apply(node)
            parentMenuMap.getOrPut(parentId) { mutableListOf() }.add(node)
        }

        for (node in menuList) {
            val nodeId = id.apply(node)
            val children = parentMenuMap[nodeId]

            //添加到下级数据中
            setSubChildren.accept(node, children?: mutableListOf())

            //如里是根节点，加入结构
            if (rootCheck.test(node)) {
                result.add(node)
            }
        }
        return result
    }

    /**
     * 树中过滤
     * @param tree  需要过滤的树
     * @param predicate  过滤条件
     * @param getChildren 获取下级数据方法，如：MenuVo::getSubMenus
     * @return List<E> 过滤后的树
     * @param <E> 泛型实体对象
    </E></E> */
    fun <E> filter(
        tree: List<E>,
        predicate: Predicate<E>,
        getChildren: Function<E, List<E>?>,
    ): List<E> {
        return tree.filter { item: E ->
            var filterAble = false
            if (predicate.test(item)) {
                val children = getChildren.apply(item)
                if (children != null) {
                    if (children.isNotEmpty()) {
                        filter(children, predicate, getChildren)
                    }
                }
                filterAble = true
            }
            filterAble
        }

        /*return tree.stream().filter(java.util.function.Predicate<E> { item: E ->
            if (predicate.test(item)) {
                val children: List<E> = getChildren.apply(item)
                if (children != null && !children.isEmpty()) {
                    filter(children, predicate, getChildren)
                }
                return@filter true
            }
            false
        }).collect<List<E>, Any>(java.util.stream.Collectors.toList<E>())*/
    }

    fun <E> filter2(
        tree: List<E>,
        predicate: Predicate<E>,
        getChildren: Function<E, MutableList<E>?>,
    ): List<E> {
        val filtered = mutableListOf<E>()
       tree.forEach { item->
           val children = getChildren.apply(item)
           if(!children.isNullOrEmpty()){
               val filteredChildren = filter2(children,predicate,getChildren)
               if(predicate.test(item)){
                   filtered.add(item)
                   getChildren.apply(item)!!.clear()
                   getChildren.apply(item)!!.addAll(filteredChildren)
               }
           }else if(predicate.test(item)){
               filtered.add(item)
           }
       }

        return filtered
    }


    /**
     * 树中搜索
     * @param tree
     * @param predicate
     * @param getSubChildren
     * @return 返回搜索到的节点及其父级到根节点
     * @param <E>
    </E> */
    fun <E> search(
        tree:MutableList<E>,
        predicate: Predicate<E>,
        getSubChildren: Function<E, MutableList<E>>,
    ): MutableList<E> {
        val iterator = tree.iterator()
        while (iterator.hasNext()) {
            val item = iterator.next()
            var childList = getSubChildren.apply(item)
            if (childList.isNotEmpty()) {
                childList = search(childList, predicate, getSubChildren)
            }
            if (!predicate.test(item) &&  childList.isEmpty()) {
                iterator.remove()
            } else{
                getSubChildren.apply(item).clear()
                if(childList.isEmpty()){
                    getSubChildren.apply(item).addAll(childList)
                }
            }
        }
        return tree
    }
}